﻿#region Usings

using System;

#endregion

namespace Yandex.Market.Api.YmlSerialization
{
    /// <summary>
    ///   The base class for all attributes defined in Yandex.Market.Api.YmlSerialization.
    /// </summary>
    [AttributeUsage(AttributeTargets.All)]
    internal abstract class YmlBaseAttribute : Attribute
    {}

    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
    internal class YmlElementOrderAttribute : YmlBaseAttribute
    {
        #region Constructors

        public YmlElementOrderAttribute(uint order)
        {
            Order = order;
        }

        #endregion

        #region Properties

        public uint Order { get; set; }

        #endregion
    }

    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
    internal class YmlAttributeOrderAttribute : YmlBaseAttribute
    {
        #region Constructors

        public YmlAttributeOrderAttribute(uint order)
        {
            Order = order;
        }

        #endregion

        #region Properties

        public uint Order { get; set; }

        #endregion
    }

    /// <summary>
    ///   Creates a comment node per each line of the comment string provided.
    ///   This attribute is applicable to classes, structures, fields, and properties.
    /// </summary>
    [AttributeUsage(
        AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlCommentAttribute : YmlBaseAttribute
    {
        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlCommentAttribute" /> class.
        /// </summary>
        /// <param name = "comment">The comment.</param>
        public YmlCommentAttribute(string comment)
        {
            Comment = comment;
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the comment.
        /// </summary>
        /// <value>The comment.</value>
        public string Comment { get; set; }

        #endregion
    }

    /// <summary>
    ///   Add this attribute to types, structs or classes which you want to override
    ///   their default serialization behaviour. This attribute is optional.
    ///   This attribute is applicable to classes and structures.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
    internal class YmlSerializableTypeAttribute : YmlBaseAttribute
    {
        #region Private Fields

        /// <summary>
        ///   determines whether the serialization options property has been explicitly
        ///   set by the user.
        /// </summary>
        private bool _isOptionSet;

        /// <summary>
        ///   Private variable to hold the serialization options
        /// </summary>
        private YmlSerializationOptions _serializationOptions = YmlSerializationOptions.SerializeNullObjects;

        #endregion

        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlSerializableTypeAttribute" /> class.
        /// </summary>
        public YmlSerializableTypeAttribute()
        {
            FieldsToSerialize = YmlSerializationFields.PublicPropertiesOnly;
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the fields which Yandex.Market.Api.YmlSerialization selects for serialization
        /// </summary>
        /// <value>The fields to serialize.</value>
        public YmlSerializationFields FieldsToSerialize { get; set; }

        /// <summary>
        ///   Gets or sets the serialization options.
        /// </summary>
        /// <value>The options.</value>
        public YmlSerializationOptions Options
        {
            get { return _serializationOptions; }

            set
            {
                _serializationOptions = value;
                _isOptionSet = true;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        ///   Determines whether the serialization options property has been explicitly
        ///   set by the user.
        /// </summary>
        /// <returns>
        ///   <c>true</c> if the serialization options property has been explicitly
        ///   set by the user; otherwise, <c>false</c>.
        /// </returns>
        public bool IsSerializationOptionSet()
        {
            return _isOptionSet;
        }

        #endregion
    }

    /// <summary>
    ///   Add this attribute to properties or fields which you wish to be serialized, when 
    ///   the enclosing class uses the <c>YmlSerializableType</c> attribute in which <c>FieldsToSerialize</c>
    ///   has been set to <c>AttributedFieldsOnly</c>.
    ///   This attribute is applicable to fields and properties.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlSerializableFieldAttribute : YmlBaseAttribute
    {}

    /// <summary>
    ///   Makes a property to appear as an attribute for the enclosing class (i.e. the parent element) if possible.
    ///   This attribute is applicable to fields and properties only.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlAttributeForClassAttribute : YmlBaseAttribute
    {}

    /// <summary>
    ///   Makes a field or property to appear as an attribute for another element, if possible.
    ///   This attribute is applicable to fields and properties.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlAttributeForAttribute : YmlBaseAttribute
    {
        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlAttributeForAttribute" /> class.
        /// </summary>
        /// <param name = "parent">The element of which the property becomes an attribute.</param>
        public YmlAttributeForAttribute(string parent)
        {
            Parent = parent;
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the element of which the property becomes an attribute.
        /// </summary>
        public string Parent { get; set; }

        #endregion
    }

    /// <summary>
    ///   Makes a field or property to appear as a value for another element, if possible.
    ///   This attribute is applicable to fields and properties.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlValueForAttribute : YmlBaseAttribute
    {
        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlAttributeForAttribute" /> class.
        /// </summary>
        /// <param name = "parent">The element of which the property becomes an attribute.</param>
        public YmlValueForAttribute(string parent)
        {
            Parent = parent;
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the element for which the property becomes a value.
        /// </summary>
        public string Parent { get; set; }

        #endregion
    }

    /// <summary>
    ///   Makes a field or property to appear as a value for its parent element, if possible.
    ///   This attribute is applicable to fields and properties.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlValueForClassAttribute : YmlBaseAttribute
    {}

    /// <summary>
    ///   Prevents serialization of some field or property.
    ///   This attribute is applicable to fields and properties.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlDontSerializeAttribute : YmlBaseAttribute
    {}

    /// <summary>
    ///   Defines an alias for the field, property, class, or struct under 
    ///   which it will be serialized. This attribute is applicable to fields, 
    ///   properties, classes, and structs.
    /// </summary>
    [AttributeUsage(
        AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct)]
    internal class YmlSerializeAsAttribute : YmlBaseAttribute
    {
        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlSerializeAsAttribute" /> class.
        /// </summary>
        /// <param name = "serializeAs">the alias for the property under which the property will be serialized.</param>
        public YmlSerializeAsAttribute(string serializeAs)
        {
            SerializeAs = serializeAs;
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the alias for the property under which the property will be serialized.
        /// </summary>
        public string SerializeAs { get; set; }

        #endregion
    }

    /// <summary>
    ///   Makes a property or field to appear as a child element 
    ///   for another element. This attribute is applicable to fields and properties.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlElementForAttribute : YmlBaseAttribute
    {
        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlElementForAttribute" /> class.
        /// </summary>
        /// <param name = "parent">The element of which the property becomes a child element.</param>
        public YmlElementForAttribute(string parent)
        {
            Parent = parent;
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the element of which the property becomes a child element.
        /// </summary>
        /// <value>The element of which the property becomes a child element.</value>
        public string Parent { get; set; }

        #endregion
    }

    /// <summary>
    ///   Controls the serialization of collection instances.
    ///   This attribute is applicable to fields and properties.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlCollectionAttribute : YmlBaseAttribute
    {
        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlCollectionAttribute" /> class.
        /// </summary>
        /// <param name = "serType">type of the serialization of the collection.</param>
        public YmlCollectionAttribute(YmlCollectionSerializationTypes serType)
        {
            SerializationType = serType;
            SeparateBy = " ";
            EachElementName = null;
            IsWhiteSpaceSeparator = true;
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the type of the serialization of the collection.
        /// </summary>
        /// <value>The type of the serialization of the collection.</value>
        public YmlCollectionSerializationTypes SerializationType { get; set; }

        /// <summary>
        ///   Gets or sets the string to separate collection items, if the Serialization type is set to <c>Serially</c>.
        /// </summary>
        /// <value>the string to separate collection items, if the Serialization Type is set to <c>Serially</c>.</value>
        public string SeparateBy { get; set; }

        /// <summary>
        ///   Gets or sets the name of each child element corresponding to the collection members, if the Serialization type is set to <c>Recursive</c>.
        /// </summary>
        /// <value>The name of each child element corresponding to the collection members, if the Serialization type is set to <c>Recursive</c>.</value>
        public string EachElementName { get; set; }

        /// <summary>
        ///   Gets or sets a value indicating whether white space characters are to be
        ///   treated as sparators or not.
        /// </summary>
        /// <value>
        ///   <c>true</c> if white space separator characters are to be
        ///   treated as sparators; otherwise, <c>false</c>.
        /// </value>
        public bool IsWhiteSpaceSeparator { get; set; }

        #endregion
    }

    /// <summary>
    ///   Specifies the behavior of the deserialization method, if the element/attribute corresponding to this property is missed in the XML input.
    ///   This attribute is applicable to fields and properties.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlErrorIfMissedAttribute : YmlBaseAttribute
    {
        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlErrorIfMissedAttribute" /> class.
        /// </summary>
        /// <param name = "treatAs">The value indicating this situation is going to be treated as Error or Warning.</param>
        public YmlErrorIfMissedAttribute(YmlExceptionTypes treatAs)
        {
            TreatAs = treatAs;
            DefaultValue = null;
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the value indicating this situation is going to be treated as Error or Warning.
        /// </summary>
        /// <value>The value indicating this situation is going to be treated as Error or Warning.</value>
        public YmlExceptionTypes TreatAs { get; set; }

        /// <summary>
        ///   Gets or sets the default value for the property if the element/attribute corresponding to this property is missed in the XML input.
        ///   Setting <c>null</c> means do nothing.
        /// </summary>
        /// <value>The default value.</value>
        public object DefaultValue { get; set; }

        #endregion
    }

    /// <summary>
    ///   Specifies the format string provided for serializing data. The format string is the parameter 
    ///   passed to the <c>ToString</c> method.
    ///   If this attribute is applied to collection classes, the format, therefore, is applied to 
    ///   the collection members.
    ///   This attribute is applicable to fields and properties.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlFormatAttribute : YmlBaseAttribute
    {
        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlFormatAttribute" /> class.
        /// </summary>
        /// <param name = "format">The format string.</param>
        public YmlFormatAttribute(string format)
        {
            Format = format;
        }

        #endregion

        #region Properties

        /// <summary>
        ///   Gets or sets the format string needed to serialize data. The format string is the parameter 
        ///   passed to the <c>ToString</c> method.
        /// </summary>
        /// <value></value>
        public string Format { get; set; }

        #endregion
    }

    /// <summary>
    ///   Specifies that a particular class, or a particular property or variable type, that is 
    ///   driven from <c>IEnumerable</c> should not be treated as a collection class/object.
    ///   This attribute is applicable to fields, properties, classes, and structs.
    /// </summary>
    [AttributeUsage(
        AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct)]
    internal class YmlNotCollectionAttribute : YmlBaseAttribute
    {}

    /// <summary>
    ///   Specifies an alias for an enum member.
    ///   This attribute is applicable to enum members.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    internal class YmlEnumAttribute : YmlBaseAttribute
    {
        #region Constructor

        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlEnumAttribute" /> class.
        /// </summary>
        /// <param name = "alias">The alias.</param>
        public YmlEnumAttribute(string alias)
        {
            Alias = alias.Trim();
        }

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets the alias for the enum member.
        /// </summary>
        /// <value>The alias for the enum member.</value>
        public string Alias { get; private set; }

        #endregion
    }

    /// <summary>
    ///   Specifies a custom serializer class for a field, property, class, or struct. Yandex.Market.Api.YmlSerialization will instantiate an object
    ///   from the specified type in this attribute, and calls appropriate methods while serializing.
    ///   This attribute is applicable to fields, properties, classes, and structs.
    /// </summary>
    [AttributeUsage(
        AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct)]
    internal class YmlCustomSerializerAttribute : YmlBaseAttribute
    {
        /// <summary>
        ///   Initializes a new instance of the <see cref = "YmlCustomSerializerAttribute" /> class.
        /// </summary>
        /// <param name = "customSerializerType">Type of the custom serializer.</param>
        public YmlCustomSerializerAttribute(Type customSerializerType)
        {
            CustomSerializerType = customSerializerType;
        }

        /// <summary>
        ///   Gets or sets the type of the custom serializer.
        /// </summary>
        /// <value>The type of the custom serializer.</value>
        public Type CustomSerializerType { get; private set; }
    }
}